#include <fstream>
#include <sstream>
#include "MundoServicio.h"
#include "ProtocoloConstantes.h"
#include "ServicioConstantes.h"

using namespace std;
using namespace TP::Servicios;
using namespace TP::Comunicacion;
using namespace TP::Threading;

MundoServicio::MundoServicio(const string &pathMundos) {
	_pathMundos = pathMundos;
}

MundoServicio::~MundoServicio() { }

void MundoServicio::iniciar() {
	_exploradorDirectorios.cargarDirectorios(_pathMundos);
}

void MundoServicio::finalizar() {
 }

void MundoServicio::mensajeEntranteManejador(IMensajero* pMensajero,
		const string& pMensaje) {
	try {
		vector<string> comando;
		this->hidratarMensaje(pMensaje, comando);

		if (MUNDO == comando[0]) {
			if (LISTAR_MUNDOS == comando [1])
				this->__listarMundos(pMensajero);

			if (LISTAR_NIVELES == comando[1])
				this->__listarNiveles(pMensajero, comando);
		}
	}
	catch (Excepcion& pEx) {
		cerr << pEx.what() << endl;
	}
}

void MundoServicio::__listarMundos(IMensajero* pMensajero) {
	std::stringstream respuesta;
	respuesta << "";

	string pathArchivo;

	TiXmlDocument xmlDoc;
	vector<string> lArchMundos;
	vector<string>::iterator it;
	TiXmlElement* mundoElement = 0;

	_mutex.lock();
	lArchMundos = _exploradorDirectorios.getDirectorios();

	for (it = lArchMundos.begin(); it != lArchMundos.end(); ++it) {

		pathArchivo = _pathMundos + (*it); // Genero el path del archivo
		FILE *docfd = fopen(pathArchivo.c_str(), "r"); // Obtengo el fd
		if (docfd) {
			if (xmlDoc.LoadFile(docfd)) { // Levanto el xml

				if (respuesta.str().length() > 0)
					respuesta << SEPARADOR_CAMPO_LISTA;

				mundoElement = xmlDoc.FirstChildElement("Mundo");
				respuesta << mundoElement->Attribute("nombre");
			}
			fclose(docfd);
		}
	}
	_mutex.unlock();
	this->notificar(pMensajero, respuesta.str());
}

void MundoServicio::__listarNiveles(IMensajero* pMensajero,
		vector<string>& pComando) {
	if (pComando.size() != 3) {
		this->notificarError(pMensajero, "Formato de comando incorrecto.");
		return;
	}
	_mutex.lock();
	std::stringstream respuesta;
	respuesta << "";
	vector<string> lArchMundos = _exploradorDirectorios.getDirectorios();

	bool encontrado = false;

	for (vector<string>::iterator it = lArchMundos.begin();
			it != lArchMundos.end() && !encontrado; ++it) {
		string pathArchivo = _pathMundos + (*it);
		FILE *docfd = fopen(pathArchivo.c_str(), "r");
		if (docfd) {
			TiXmlDocument xmlDoc;

			if (xmlDoc.LoadFile(docfd)) {
				TiXmlElement* mundoElement = xmlDoc.FirstChildElement("Mundo");
				string nombre = pComando [2];

				if (encontrado = (mundoElement->Attribute("nombre") == nombre)){
					TiXmlElement* elementAux = 
							mundoElement->FirstChildElement(); /*Niveles*/

					if (elementAux) {
						// El mundo posee niveles definidos.
						elementAux = elementAux->FirstChildElement();

						while (NULL != elementAux) {
							if (respuesta.str().length() > 0)
								respuesta << SEPARADOR_CAMPO_LISTA;
							respuesta << elementAux->Attribute("id");
							elementAux = elementAux->NextSiblingElement();
						}
					}
				}
			}
			fclose(docfd);
		}
	}
	_mutex.unlock();
	if (encontrado)
		this->notificar(pMensajero, respuesta.str());
	else
		this->notificar(pMensajero, NULO);
}

Mundo* MundoServicio::getMundoPorNombre(const string& pNombreMundo) {
	_mutex.lock();
	Mundo* mundo = NULL;
	try {
		// El nombre del mundo se especifica en el nombre del archivo.
		string path = this->_pathMundos;
		path += pNombreMundo;
		path += ".xml";

		ifstream stream(path.c_str());

		if (stream.is_open()) {
			// El mundo existe.  Lo hidrato y lo retorno.

			// Cargo el mundo en un string.
			std::stringstream strstream;
			string item = "";

			while (std::getline(stream, item, '\n'))
				strstream << item << endl;

			// Hidrato el mundo y lo retorno.
			mundo = Mundo::crearDeXML(strstream.str());
		}
	}
	catch (Excepcion& pEx) {
		cerr << pEx.what() << endl;
	}
	_mutex.unlock();
	return mundo;
}